<?php
/**
 * >User: nsj
 * UEditor编辑器通用上传类
 * 图片管理图片上传
 * 图片命名规则 原图前缀 b_ ，中图 m_ ，小图 s_ ，后加时间戳加4位随机数
 * 数据库存储图片规则 路径字段 用户ID/分类ID/年月日 ，图片名称字段 无前缀的10位时间戳加4位随机数加图片类型
 */
 
class Uploader
{
    private $fileField;            //文件域名
    private $files;                 //文件上传对象
    private $config;               //配置信息
    private $oriName;              //原始文件名
    private $fileName;             //新文件名
    private $fullName;             //完整文件名,即从当前配置目录开始的URL
    private $fileSize;             //文件大小
    private $fileType;             //文件类型
    private $stateInfo;            //上传状态信息,
	private $width = '';            //原始图片宽度
	private $height = '';            //原始图片高度
	
	private $baseurl = 'uploads/'; //上传路径
	private $rtfullName = '/'; //网站根目录
	
    private $stateMap = array(    //上传状态映射表，国际化用户需考虑此处数据的国际化
        "SUCCESS" ,                //上传成功标记，在UEditor中内不可改变，否则flash判断会出错
        "文件大小超出 upload_max_filesize 限制" ,
        "文件大小超出 MAX_FILE_SIZE 限制" ,
        "文件未被完整上传" ,
        "没有文件被上传" ,
        "上传文件为空" ,
        "POST" => "文件大小超出 post_max_size 限制" ,
        "SIZE" => "文件大小超出网站限制" ,
        "TYPE" => "不允许的文件类型" ,
        "DIR" => "目录创建失败" ,
        "IO" => "输入输出错误" ,
        "UNKNOWN" => "未知错误" ,
        "MOVE" => "文件保存时出错"
    );

    /**
     * 构造函数
     * @param string $fileField 表单名称
     * @param array $config  配置项
     * @param bool $base64  是否解析base64编码，可省略。若开启，则$fileField代表的是base64编码的字符串表单名
     */
    public function index( $fileField , $configs , $base64 = false )
    {
		$this->fileField = $fileField;
		if($configs['savePath'] == ''){$configs['savePath'] = $configs['save'];}
        $this->config = $configs;
		if($configs['save'] != ''){$this->baseurl = $configs['save'];}
		if($configs['rsave'] != ''){$this->rtfullName = $configs['rsave'];}
        $this->stateInfo = $this->stateMap[ 0 ];
        $this->upfile( $base64 );
    }

    /**
     * 上传文件的主处理方法
     * @param $base64
     * @return mixed
     */
    private function upfile( $base64 )
    {
        //处理base64上传
        if ( "base64" == $base64 ) {
            $content = $_POST[ $this->fileField ];
            $this->base64ToImage( $content );
            return;
        }
		//var_dump($this->fileField);exit();
        //处理普通上传
		if ( !empty($this->fileField) ) {
			$filex = $this->files = $_FILES[ $this->fileField ];
		}
        if ( !$filex ) {
            $this->stateInfo = $this->getStateInfo( 'POST' );
            return;
        }
        if ( $this->files[ 'error' ] ) {
            $this->stateInfo = $this->getStateInfo( $filex[ 'error' ] );
            return;
        }
        if ( !is_uploaded_file( $filex[ 'tmp_name' ] ) ) {
            $this->stateInfo = $this->getStateInfo( "UNKNOWN" );
            return;
        }

        $this->oriName = $filex[ 'name' ];
        $this->fileSize = $filex[ 'size' ];
        $this->fileType = $this->getFileExt();
        if ( !$this->checkSize() ) {
            $this->stateInfo = $this->getStateInfo( "SIZE" );
            return;
        }
        if ( !$this->checkType() ) {
            $this->stateInfo = $this->getStateInfo( "TYPE" );
            return;
        }
		$thumbnails = $this->config[ "thumbnails" ];
		$tbcount = count($thumbnails);
		$tbs = "";
		if ( $tbcount > 0 )
		{
			$tbs = $thumbnails[0][0];
		}
		$picname = $this->getName();
		
        $this->fullName = $this->getFolder() . $tbs . $picname;
        if ( $this->stateInfo == $this->stateMap[ 0 ] ) {
            if ( move_uploaded_file( $filex[ "tmp_name" ] , $this->fullName ) ) {
            	$this->getaspect ( $this->fullName );//高宽
				if(($this->width > $thumbnails[0][1]) or ($this->height > $thumbnails[0][2]))
				{
					$toFile = $this->fullName;
					$toW = $thumbnails[0][1];
					$toH = $thumbnails[0][2];
					$this->imageresize( $this->fullName, $toW, $toH, $toFile );
					$this->getaspect ( $this->fullName );//重新获取高宽
				}
				
				if ( $tbcount > 1 )
				{
					for ( $i = 1; $i < $tbcount; $i++ )
					{
						$tbs = $thumbnails[ $i ][0];
						$toFile = $this->getFolder() . $tbs . $picname;
						$toW = $thumbnails[ $i ][1];
						$toH = $thumbnails[ $i ][2];
						$this->imageresize( $this->fullName, $toW, $toH, $toFile );
					}
				}
            }
			else
			{
			    $this->stateInfo = $this->getStateInfo( "MOVE" );
			}
        }
    }

    /**
     * 处理base64编码的图片上传
     * @param $base64Data
     * @return mixed
     */
    private function base64ToImage( $base64Data )
    {
        $img = base64_decode( $base64Data );
        $this->fileName = time() . rand( 1000 , 9999 ) . ".png";
        $this->fullName = $this->getFolder() . '/' . $this->fileName;
        if ( !file_put_contents( $this->fullName , $img ) ) {
            $this->stateInfo = $this->getStateInfo( "IO" );
            return;
        }
        $this->oriName = "";
        $this->fileSize = strlen( $img );
        $this->fileType = ".png";
    }

    /**
     * 获取当前上传成功文件的各项信息
     * @return array
     */
    public function getFileInfo()
    {
        $this->rtfullName .= str_replace('../','',$this->fullName);
		return array(
            "originalName" => $this->oriName ,//原始文件名
            "name" => $this->fileName ,//新文件名
            "url" => $this->rtfullName ,//返回的地址
            "size" => $this->fileSize ,//文件大小
            "type" => $this->fileType ,//文件类型
			"width" => $this->width ,//文件宽度仅限图片
			"height" => $this->height ,//文件高度仅限图片
            "state" => $this->stateInfo//上传状态，上传成功时必须返回"SUCCESS"
        );
    }
	
	/**
     * 获取高宽
     * @param $errCode
     * @return string
     */
	private function getaspect ( $img )
	{
		$srcInfo = getimagesize($img);
		switch ($srcInfo[2])
        {
            case 1:
				$im = imagecreatefromgif($img);
                break;
            case 2:
				$im = imagecreatefromjpeg($img);
                break;
            case 3:
				$im = imagecreatefrompng($img);
                break;
        }
        $this->width = imagesx($im);
        $this->height = imagesy($im);
		
	}
	
    /**
     * 上传错误检查
     * @param $errCode
     * @return string
     */
    private function getStateInfo( $errCode )
    {
        return !$this->stateMap[ $errCode ] ? $this->stateMap[ "UNKNOWN" ] : $this->stateMap[ $errCode ];
    }

    /**
     * 重命名文件
     * @return string
     */
    private function getName()
    {
        return $this->fileName = time() . rand( 1000 , 9999 ) .'.'. $this->getFileExt();
    }

    /**
     * 文件类型检测
     * @return bool
     */
    private function checkType()
    {
        return in_array( $this->getFileExt() , $this->config[ "allowFiles" ] );
    }

    /**
     * 文件大小检测
     * @return bool
     */
    private function  checkSize()
    {
        return $this->fileSize <= ( $this->config[ "maxSize" ] * 1024 );
    }

    /**
     * 获取文件扩展名
     * @return string
     */
    private function getFileExt()
    {
        return strtolower( substr( strrchr( $this->files[ "name" ] , '.' ) ,1 ));
    }

    /**
     * 按照日期自动创建存储文件夹
     * @return string
     */
    private function getFolder()
    {
		$pathStr = $this->baseurl.$this->config[ "savePath" ];
        $adir = explode('/',$pathStr);
        if ( !file_exists( $pathStr ) ) {
            if ( !mkdir( $pathStr , 0777 , true ) ) {
                return false;
            }
        }
		if ( strrchr( $pathStr , "/" ) != "/" ) {
            $pathStr .= "/";
        }
        return $pathStr;
    }
	
	/**
     * 等比缩图
     * @return true
     */
	private function imageresize($srcFile, $toW, $toH, $toFile='')
    {
        if($toFile=='') $toFile = $srcFile;
        $srcInfo = getimagesize($srcFile);
        switch ($srcInfo[2])
        {
            case 1:
				$im = imagecreatefromgif($srcFile);
                break;
            case 2:
				$im = imagecreatefromjpeg($srcFile);
                break;
            case 3:
				$im = imagecreatefrompng($srcFile);
                break;
        }
        $srcW=imagesx($im);
        $srcH=imagesy($im);
        $toWH=$toW/$toH;
        $srcWH=$srcW/$srcH;
        if($toWH<=$srcWH)
        {
            $ftoW=$toW;
            $ftoH=$ftoW*($srcH/$srcW);
        }
        else
        {
            $ftoH=$toH;
            $ftoW=$ftoH*($srcW/$srcH);
        }
        if($srcW > $toW || $srcH > $toH)
        {
            if($srcInfo[2] == 1){
				if(extension_loaded('imagick'))
				{
					$this->imagick_resize($srcFile,$toFile,$srcInfo[2],$ftoW,$ftoH);
				} else {
					copy($srcFile,$toFile);
				}
			}else{
				if(extension_loaded('imagick'))
				{
					$this->imagick_resize($srcFile,$toFile,$srcInfo[2],$ftoW,$ftoH);
				} else {
					if(function_exists("imagecreatetruecolor"))
					{
						$ni = imagecreatetruecolor($ftoW,$ftoH);
						if($ni)
						{
							imagealphablending($ni,false);
							imagesavealpha($ni,true);
							imagecopyresampled($ni,$im,0,0,0,0,$ftoW,$ftoH,$srcW,$srcH);
						}
						else
						{
							$ni=imagecreate($ftoW,$ftoH);
							imagecopyresized($ni,$im,0,0,0,0,$ftoW,$ftoH,$srcW,$srcH);
						}
					}
					else
					{
						$ni=imagecreate($ftoW,$ftoH);
						imagecopyresized($ni,$im,0,0,0,0,$ftoW,$ftoH,$srcW,$srcH);
					}
					switch ($srcInfo[2])
					{
						case 1:
							imagegif($ni,$toFile);
							break;
						case 2:
							imagejpeg($ni,$toFile,100);
							break;
						case 3:
							imagepng($ni,$toFile);
							break;
						default:
							return FALSE;
					}
					imagedestroy($ni);
					imagedestroy($im);
				}
			}
		}else{
			copy($srcFile,$toFile);
		}
        return TRUE;
    }
	
	private function imagick_resize($srcFile,$toFile,$type='',$width = 100, $height = 100)
	{
		$image = new Imagick( $srcFile );
		if($type == 1)
        {
			$canvas = new Imagick();
			$images = $image->coalesceImages();
			foreach($images as $frame){
				$img = new Imagick();
				$img->readImageBlob($frame);
				$img->thumbnailImage( $width, $height, false );
				$canvas->addImage( $img );
				$canvas->setImageDelay( $img->getImageDelay() );
		   }
		   $image->destroy();
		   $canvas->writeImages($toFile, true);
		}
        else
        {
        	$image->thumbnailImage( $width, $height, true );
			$image->writeImage($toFile);
        }
	}
}

/*end*/